use axum::{
    body::Body,
    http::{HeaderMap, StatusCode, header},
    response::{IntoResponse, Response},
};
use serde::Serialize;
use utoipa::ToSchema;

#[derive(Serialize, ToSchema)]
pub struct AppResult<T> {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<T>,
    pub code: i32,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
}

impl<T: Serialize> IntoResponse for AppResult<T> {
    fn into_response(self) -> Response {
        match serde_json::to_string(&self) {
            Ok(body) => Response::builder()
                .header(header::CONTENT_TYPE, "application/json")
                .body(Body::from(body))
                .unwrap(),
            Err(_) => {
                let error_body = r#"{"code":500,"message":"Serialization error"}"#;
                Response::builder()
                    .header(header::CONTENT_TYPE, "application/json")
                    .body(Body::from(error_body))
                    .unwrap()
            }
        }
    }
}

impl<T: Serialize> AppResult<T> {
    pub fn success() -> Self {
        Self {
            data: None,
            code: 200,
            message: Some("success".to_string()),
        }
    }
}
